//shortcut to BaseEnum.getClause
var baseEnum_getClause,
//default expression to value clauses
default_clauses_returnCurrent = jMass.expr("x => x"),
//default expression to equality comparer
default_clauses_equalityComparer = jMass.expr("x,y => x === y");


jMass.extend({
    // return an Enumerator object for obj.
    getEnum: function(obj) {
        // return obj if it is an Enumerator;
        return !obj ? null
                : obj.isEnum ? obj
        // or, if obj has the toEnum method, call it.
                : obj.toEnum ? obj.toEnum()
                : null;
    },

    //to hold enumerators classes
    Enum: {
        //enumerators classes
        $classes: [],
        //enumerators methods
        $methods: []
    },

    //register a new enum class
    regEnumClass: function(name, classObj) {
        jMass.Enum.$classes.push({ name: name, obj: classObj });
    },

    //register a enumerator method
    regEnumMethod: function(name, method) {
        jMass.Enum.$methods.push({ name: name, method: method });
    },

    $initEnums: function() {
        //variables in for statement
        var cls, mthd, obj, isEn;

        for (var i = 0, len = this.Enum.$classes.length; i < len; i++) {
            cls = this.Enum.$classes[i];
            obj = cls.obj;
            isEn = obj.prototype.isEnum === true;

            if (isEn) this.Enum[cls.name] = obj;

            //implement
            for (var j = 0, lenj = this.Enum.$methods.length; j < lenj; j++) {
                mthd = this.Enum.$methods[j];
                if (obj.prototype[mthd.name] == undefined) {
                    if (isEn)
                        obj.prototype[mthd.name] = mthd.method;
                    obj.prototype["_" + mthd.name] = mthd.method;
                }
            }
        }
    },

    init: function(o) {
        this.$initEnums();
    }
});

// define the enumerator base object
var BaseEnum = jMass.Enum.BaseEnum = jMass.define({
    // isEnum
    isEnum: true,

    // name of enumerator
    name: "enumerator",

    //store a unique id for this enumerator
    guid: 0,

    // the source object that provide the data to enumerate
    source: null,

    // current item
    current: null,

    // next() function
    // MUST return true when new value is assigned to this.current.
    // ** commented here for sake of speed
    // next: function() { return false; },

    // reset enumerator state
    // reset: function() { },

    // perform some initialization code for enumerator
    constructor: function(source) {
        //assign a unique id
        this.guid = ++jMass.guid;

        this.source = source;

        //reset the enumerator
        this.reset();
    },

    getClause: function(clause, defaultIfEmpty) {
        return jMass.getExpr(clause || defaultIfEmpty);
    },

    //toEnum
    toEnum: function() {
        return this;
    }
});

baseEnum_getClause = jMass.Enum.BaseEnum.prototype.getClause;

/* base enumerator */
var fluentQryBaseEnum = jMass.Enum.BaseFluentEnum = BaseEnum.extend({
    // override base constructor
    constructor: function(source, a, b, c) {
        //call base passing source enumerator
        this.base(jMass.getEnum(source));

        //call prepare method
        if (this.prepare)
            this.prepare.call(this, a, b, c);

        //reset
        this.reset();
    },
    // constructor will call prepare on decendants.
    // ** commented here for sake of speed
    //prepare: function() { },
    reset: function() {
        this.source.reset();
        this.current = this.source.current;
    }
});



